﻿using CIS.Web.Common;
using CIS.Web.Models;
using CIS.Web.Properties;
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.IO;
using System.Linq;
using System.Linq.Dynamic;
using System.Net.Mail;
using System.Threading.Tasks;
using System.Web.Mvc;
using static System.Net.Mime.MediaTypeNames;

namespace CIS.Web.Controllers
{
	[RoutePrefix("ConferenceReview")]
	public class ConferenceReviewController : BaseDbController
	{
		[Route("Index/{ConferenceId}")]
		public async Task<ActionResult> Index(string conferenceId)
		{
			string controller = RouteData.Values["controller"].ToString();
			string actionName = RouteData.Values["action"].ToString();
			Utility.InsertLog(LoginUser, Request.Url.ToString(), controller, actionName, "Index", conferenceId);

			var conferenceMaster = await DbContext.ConferenceMaster.AsNoTracking()
					.FirstOrDefaultAsync(x => x.Status == ConstValues.Status.正常 &&
						x.ID == conferenceId);

			ViewBag.ConferenceId = conferenceId;
			ViewBag.ConferenceName = conferenceMaster.ConferenceName;
			ViewBag.ControllerName = Resources.ConferenceReview;
			ViewBag.Language = conferenceMaster.IsInternational ? ConstValues.Language.En : ConstValues.Language.Cn;

			var reviewPerson = await DbContext.ReviewPersonMaster.AsNoTracking()
					.FirstOrDefaultAsync(x => x.ConferenceId == conferenceId &&
						x.UserId == LoginUser.UserID);

			var model = new ConferenceReviewModel();
			model.ConferenceId = conferenceId;
			model.AllowToReview = conferenceMaster.ReviewStartDate.Value <= DateTime.Now && conferenceMaster.ReviewEndDate.Value >= DateTime.Now ? true : false;
			model.IsReview = conferenceMaster.IsReview;
			if (reviewPerson != null && reviewPerson.IsFinalReviewer)
			{
				model.IsFinalReviewer = reviewPerson.IsFinalReviewer;
			}
			if (reviewPerson != null && reviewPerson.IsFirstReviewer)
			{
				model.IsFirstReviewer = reviewPerson.IsFirstReviewer;
			}
			model.HasAddToReviewer = reviewPerson == null ? false : true;
			model.UserId = LoginUser.UserID;
			model.Form = Utility.GetContributeItem(conferenceId);
			LoginUser.ConferenceFunctionIdList = Utility.GetConferenceFunctionIdList(conferenceId);
			return View(model);
		}

		public async Task<JsonCamelCaseResult> GetData(int? page, int? rows, string sort, string order, ConferenceReviewModel model)
		{
			int take = rows ?? ConstValues.DefaultGridRows;
			int skip = ((page ?? 1) - 1) * take;

			var isShowAll = LoginUser.IsSSA || LoginUser.CSAList.Contains(model.ConferenceId) ||
					(Utility.HasConferenceRole(LoginUser, model.ConferenceId, ConstValues.FunctionId.ConferenceReview, RoleType.浏览) &&
					Utility.HasConferenceRole(LoginUser, model.ConferenceId, ConstValues.FunctionId.ConferenceReview, RoleType.添加) &&
					Utility.HasConferenceRole(LoginUser, model.ConferenceId, ConstValues.FunctionId.ConferenceReview, RoleType.修改) &&
					Utility.HasConferenceRole(LoginUser, model.ConferenceId, ConstValues.FunctionId.ConferenceReview, RoleType.删除));

			if (!string.IsNullOrWhiteSpace(model.SelfReview))
			{
				isShowAll = false;
			}

			var contributeIdList = await DbContext.ReviewInfo.AsNoTracking()
					.Where(x => !string.IsNullOrEmpty(x.Status) &&
						x.ConferenceId == model.ConferenceId &&
						x.UserId == LoginUser.UserID)
					.Select(x => x.ContributeId)
					.ToListAsync();

			var sql = from info in DbContext.ConferenceContributeInfo.AsNoTracking()
						.Where(x => x.ConferenceId == model.ConferenceId &&
							(isShowAll ? true : contributeIdList.Contains(x.ID)))
				  join conferenceMaster in DbContext.ConferenceMaster.AsNoTracking().Where(x => x.Status == ConstValues.Status.正常)
					on info.ConferenceId equals conferenceMaster.ID
				  join reportMaster in DbContext.ReportMaster.AsNoTracking().Where(x => x.Status == ConstValues.Status.正常)
					on info.ReportId equals reportMaster.ID into reports
				  from report in reports.DefaultIfEmpty()
				  join topicMaster in DbContext.TopicMaster.AsNoTracking().Where(x => x.Status == ConstValues.Status.正常)
					on info.TopicId equals topicMaster.ID into topics
				  from topic in topics.DefaultIfEmpty()
				  join essayMaster in DbContext.EssayMaster.AsNoTracking().Where(x => x.Status == ConstValues.Status.正常)
					on info.EssayId equals essayMaster.ID into essays
				  from essay in essays.DefaultIfEmpty()
				  orderby info.Sort ascending, info.UpdateDate descending
				  select new ReviewDataModel
				  {
					  ContributeId = info.ID,
					  EssayTitle = info.EssayTitle,
					  TopicId = info.TopicId,
					  TopicName = string.IsNullOrEmpty(topic.TopicName) ? string.Empty : topic.TopicName,
					  EssayId = info.EssayId,
					  EssayType = string.IsNullOrEmpty(essay.EssayType) ? string.Empty : essay.EssayType,
					  ReportId = info.ReportId,
					  ReportType = string.IsNullOrEmpty(report.ReportType) ? string.Empty : report.ReportType,
					  ContributationStatus = info.ContributationStatus,
					  Sort = info.Sort,
					  IsReview = conferenceMaster.IsReview,
					  ConferenceId = info.ConferenceId,
					  HasSend = info.HasSend,
					  AdminStatus = info.AdminStatus,
					  AdminRemark = info.AdminRemark,
				  };

			if (!string.IsNullOrEmpty(model.SelTopic))
			{
				sql = sql.Where(x => x.TopicId == model.SelTopic);
			}

			if (!string.IsNullOrEmpty(model.SelReport))
			{
				sql = sql.Where(x => x.ReportId == model.SelReport);
			}

			if (!string.IsNullOrEmpty(model.SelEssay))
			{
				sql = sql.Where(x => x.EssayId == model.SelEssay);
			}

			if (!string.IsNullOrEmpty(model.ContributeStatus))
			{
				sql = sql.Where(x => !string.IsNullOrEmpty(x.AdminStatus) ?
						x.AdminStatus == model.ContributeStatus :
						x.ContributationStatus == model.ContributeStatus);
			}

			if (model.HasSend.HasValue)
			{
				sql = sql.Where(x => x.HasSend == model.HasSend);
			}

			if (!string.IsNullOrEmpty(model.SelIdName))
			{
				var contributeAuthorList = DbContext.AuthorInfo.AsNoTracking()
						.Where(x => x.ContributeId.Contains(model.SelIdName) ||
							x.FullName.Contains(model.SelIdName) ||
							x.Mobile.Contains(model.SelIdName) ||
							x.Mail.Contains(model.SelIdName))
						.Select(x => x.ContributeId)
						.ToList();

				var contributeAffiliationList = DbContext.AffiliationInfo.AsNoTracking()
						.Where(x => x.ContributeId.Contains(model.SelIdName) ||
							x.Mail.Contains(model.SelIdName) ||
							x.Affiliation.Contains(model.SelIdName))
						.Select(x => x.ContributeId)
						.ToList();

				sql = sql.Where(x => contributeAuthorList.Contains(x.ContributeId) || contributeAffiliationList.Contains(x.ContributeId));
			}

			int total = await sql.CountAsync();

			if (!string.IsNullOrEmpty(sort))
			{
				sql = sql.OrderBy(sort + ConstValues.chrSpace + order).Skip(skip).Take(take);
			}
			else
			{
				sql = sql.OrderByDescending(x => x.ContributeId).Skip(skip).Take(take);
			}

			var sqlResult = await sql.ToListAsync();

			sqlResult.ForEach(y =>
			{
				var useridList = DbContext.ReviewInfo.AsNoTracking()
					.Where(x => x.ContributeId == y.ContributeId &&
						x.ConferenceId == y.ConferenceId)
					.Select(x => x.UserId)
					.Distinct().ToList();
				y.UserIdList = useridList;

				var firstAuthorInfo = DbContext.AuthorInfo.AsNoTracking()
					.Where(x => x.ContributeId == y.ContributeId &&
						x.ConferenceId == y.ConferenceId)
					.OrderBy(x => x.Sort)
					.FirstOrDefault();

				var affiliationList = DbContext.AffiliationInfo.AsNoTracking()
					.Where(x => x.Status == ConstValues.Status.正常 &&
						x.ConferenceId == y.ConferenceId &&
						x.ContributeId == y.ContributeId &&
						x.Mail == firstAuthorInfo.Mail)
					.OrderBy(x => x.Sort)
					.ThenBy(x => x.Affiliation)
					.Select(x => x.Affiliation)
					.ToList();

				y.FullName = firstAuthorInfo.FullName;
				y.Affiliation = affiliationList.Count > 0 ? string.Join(ConstValues.strSemicolon, affiliationList) : string.Empty;
			});

			return JsonCamelCase(new
			{
				Total = total,
				Rows = sqlResult,
			},
			JsonRequestBehavior.AllowGet);
		}

		[HttpPost]
		[ValidateAntiForgeryToken]
		public async Task<JsonResult> JuniorReview(ConferenceReviewModel model)
		{
			string controller = RouteData.Values["controller"].ToString();
			string actionName = RouteData.Values["action"].ToString();
			Utility.InsertLog(LoginUser, Request.Url.ToString(), controller, actionName, "Index", model.ConferenceId);

			var result = await DbContext.ReviewInfo
					.FirstOrDefaultAsync(x => x.ConferenceId == model.ConferenceId &&
						x.ContributeId == model.ContributeId &&
						x.UserId == LoginUser.UserID &&
						x.IsFinalReview == false);

			if (result == null)
			{
				return JsonCamelCase(Utility.CreateFailJsonResult(Resources.MsgRecordNotExist),
						JsonRequestBehavior.AllowGet);
			}

			using (var transaction = DbContext.Database.BeginTransaction())
			{
				if (model.Quality.HasValue)
				{
					result.Quality = model.Quality.Value;
				}
				if (model.Evaluation.HasValue)
				{
					result.Evaluation = model.Evaluation.Value;
				}
				result.Remark = !string.IsNullOrEmpty(model.Remark) ? model.Remark : string.Empty;
				result.Advantage = !string.IsNullOrEmpty(model.Advantage) ? model.Advantage : string.Empty;
				result.Defect = !string.IsNullOrEmpty(model.Defect) ? model.Defect : string.Empty;
				if (model.Result == ConstValues.ContributationStatus.转投)
				{
					result.Result = ConstValues.ContributationStatus.待审;
				}
				else
				{
					result.Result = model.Result == ConstValues.ContributationStatus.不录用 ?
							ConstValues.ContributationStatus.不录用 :
							ConstValues.ContributationStatus.录用;
				}
				result.Others = !string.IsNullOrEmpty(model.Others) ? model.Others : string.Empty;
				result.Updater = LoginUser.UserName;
				result.UpdateIP = LoginUser.IP;
				result.UpdateDate = DateTime.Now;

				var contribute = await DbContext.ConferenceContributeInfo.FirstOrDefaultAsync(x => x.ID == model.ContributeId);

				if (model.Result == ConstValues.ContributationStatus.转投)
				{
					if (model.TopicName != null && contribute.TopicId != model.TopicName)
					{
						contribute.TopicId = model.TopicName;
						contribute.ContributationStatus = ConstValues.ContributationStatus.待审;
						contribute.Updater = LoginUser.UserName;
						contribute.UpdateIP = LoginUser.IP;
						contribute.UpdateDate = DateTime.Now;
					}
				}
				else
				{
					contribute.ContributationStatus = ConstValues.ContributationStatus.审核中;
					if (model.ReportType != null && contribute.ReportId != model.ReportType)
					{
						contribute.ReportId = model.ReportType;
					}

					var conferenceMaster = await DbContext.ConferenceMaster.AsNoTracking()
							.FirstOrDefaultAsync(x => x.ID == model.ConferenceId);
					if (!conferenceMaster.IsReview)
					{
						//其他的审核
						var ReviewInfoCount = await DbContext.ReviewInfo.AsNoTracking()
								.Where(x => x.ContributeId == model.ContributeId &&
									x.UserId != LoginUser.UserID &&
									x.IsFinalReview == false &&
									x.Result == ConstValues.ContributationStatus.待审)
								.CountAsync();

						if (ReviewInfoCount == 0)
						{
							//录用个数
							var AcceptCount = await DbContext.ReviewInfo.AsNoTracking()
									.Where(x => x.ContributeId == model.ContributeId &&
										x.IsFinalReview == false &&
										x.Result == ConstValues.ContributationStatus.录用)
									.CountAsync();

							//不录用个数
							var RejectCount = await DbContext.ReviewInfo.AsNoTracking()
									.Where(x => x.ContributeId == model.ContributeId &&
										x.IsFinalReview == false &&
										x.Result == ConstValues.ContributationStatus.不录用)
									.CountAsync();

							if (model.Result == ConstValues.ContributationStatus.录用)
							{
								AcceptCount = AcceptCount + 1;
							}
							else
							{
								RejectCount = RejectCount + 1;
							}

							if (AcceptCount > RejectCount)
							{
								contribute.ContributationStatus = ConstValues.ContributationStatus.录用;
							}
							else
							{
								contribute.ContributationStatus = ConstValues.ContributationStatus.不录用;
							}

							contribute.Updater = LoginUser.UserName;
							contribute.UpdateIP = LoginUser.IP;
							contribute.UpdateDate = DateTime.Now;
						}
					}
				}

				await DbContext.SaveChangesAsync();
				transaction.Commit();
			}

			return JsonCamelCase(Utility.CreateSuccessJsonResult(Resources.SuccessSubmit),
					JsonRequestBehavior.AllowGet);
		}

		[HttpPost]
		[ValidateAntiForgeryToken]
		public async Task<JsonResult> FinalReview(ConferenceReviewModel model)
		{
			string controller = RouteData.Values["controller"].ToString();
			string actionName = RouteData.Values["action"].ToString();
			Utility.InsertLog(LoginUser, Request.Url.ToString(), controller, actionName, "Index", model.ConferenceId);

			var result = await DbContext.ReviewInfo
					.FirstOrDefaultAsync(x => x.ConferenceId == model.ConferenceId &&
						x.ContributeId == model.ContributeId &&
						x.UserId == LoginUser.UserID &&
						x.IsFinalReview == true);

			if (result == null)
			{
				return JsonCamelCase(Utility.CreateFailJsonResult(Resources.MsgRecordNotExist),
						JsonRequestBehavior.AllowGet);
			}

			var conferenceMaster = await DbContext.ConferenceMaster.AsNoTracking()
					.FirstOrDefaultAsync(x => x.ID == model.ConferenceId);

			if (!conferenceMaster.IsReview)
			{
				return JsonCamelCase(Utility.CreateFailJsonResult(Resources.MsgConferenceNoFinalReview),
						JsonRequestBehavior.AllowGet);
			}

			using (var transaction = DbContext.Database.BeginTransaction())
			{
				result.Advantage = model.Advantage;
				result.Result = model.FinalResult;
				result.Updater = LoginUser.UserName;
				result.UpdateIP = LoginUser.IP;
				result.UpdateDate = DateTime.Now;

				var contribute = await DbContext.ConferenceContributeInfo.FirstOrDefaultAsync(x => x.ID == model.ContributeId);
				contribute.ContributationStatus = model.FinalResult;
				contribute.Updater = LoginUser.UserName;
				contribute.UpdateIP = LoginUser.IP;
				contribute.UpdateDate = DateTime.Now;

				await DbContext.SaveChangesAsync();
				transaction.Commit();
			}

			return JsonCamelCase(Utility.CreateSuccessJsonResult(Resources.SuccessSubmit),
					JsonRequestBehavior.AllowGet);
		}

		[HttpPost]
		[ValidateAntiForgeryToken]
		[ValidateInput(false)]
		public async Task<JsonResult> SendMail(ConferenceReviewModel model)
		{
			string controller = RouteData.Values["controller"].ToString();
			string actionName = RouteData.Values["action"].ToString();
			Utility.InsertLog(LoginUser, Request.Url.ToString(), controller, actionName, "Index", model.ConferenceId);

			var conferenceContributeInfo = await DbContext.ConferenceContributeInfo.AsNoTracking()
					.FirstOrDefaultAsync(x => x.ID == model.ContributeId &&
						x.ConferenceId == model.ConferenceId);

			if (conferenceContributeInfo.ContributationStatus != ConstValues.ContributationStatus.录用 &&
				conferenceContributeInfo.ContributationStatus != ConstValues.ContributationStatus.不录用)
			{
				return JsonCamelCase(Utility.CreateFailJsonResult(Resources.MsgReviewResultMailError),
							JsonRequestBehavior.AllowGet);
			}

			var conferenceMaster = await DbContext.ConferenceMaster.AsNoTracking()
					.FirstOrDefaultAsync(x => x.Status == ConstValues.Status.正常 &&
						x.ID == model.ConferenceId);

			var conferenceNotice = await DbContext.ConferenceNoticeMaster.AsNoTracking()
					.FirstOrDefaultAsync(x => x.ID == model.ConferenceId);

			var dateTimeNow = DateTime.Now.ToString("yyyyMMddHHmmss");

			//图章img
			var stampFile = string.Empty;
			if (!string.IsNullOrEmpty(conferenceNotice.PicForStamp))
			{
				var fileName = Path.GetFileName(conferenceNotice.PicForStamp);
				var pfolder = Path.Combine(Server.MapPath(ConstValues.ConferenceImg), conferenceNotice.ConferenceNickName);
				var pFullPath = Path.Combine(pfolder, fileName);

				if (System.IO.File.Exists(pFullPath))
				{
					var stampFolder = Server.MapPath(Path.Combine(ConstValues.ConferenceImg, conferenceNotice.ConferenceNickName));
					var stampFileName = Path.GetFileName(conferenceNotice.PicForStamp);
					stampFile = Path.Combine(stampFolder, stampFileName);
				}
			}

			var pdfFolder = Server.MapPath(Path.Combine(ConstValues.MailAttachment, conferenceNotice.ConferenceNickName));
			var pdfFile = pdfFolder + ConstValues.InvitationLetterPdf + "_" + dateTimeNow + ".pdf";

			Utility.CreatePdf(conferenceMaster, conferenceNotice, stampFile, pdfFile, LoginUser.UserName, conferenceContributeInfo);

			var conferenceMailServerMaster = await DbContext.ConferenceMailServerMaster.AsNoTracking()
					.FirstOrDefaultAsync(x => x.Status == ConstValues.Status.正常 &&
						x.MailType == ConstValues.MailType.投稿服务邮箱 &&
						x.ConferenceId == model.ConferenceId);

			if (conferenceMailServerMaster == null)
			{
				conferenceMailServerMaster = await DbContext.ConferenceMailServerMaster.AsNoTracking()
						.FirstOrDefaultAsync(x => x.Status == ConstValues.Status.正常 &&
							x.MailType == ConstValues.MailType.会议邮箱 &&
							x.ConferenceId == model.ConferenceId);
			}

			var authorList = await DbContext.AuthorInfo.AsNoTracking()
					.Where(x => x.ConferenceId == model.ConferenceId &&
						x.ContributeId == model.ContributeId)
					.ToListAsync();

			var strMsg = string.Empty;
			if (conferenceMailServerMaster != null)
			{
				var allAuthor = string.Join(conferenceMaster.IsInternational ? ConstValues.strComma : ConstValues.strCommaCn,
						authorList.OrderBy(x => x.Sort).ThenBy(x => x.FullName).Select(x => x.FullName));

				var status = !string.IsNullOrEmpty(conferenceContributeInfo.AdminStatus) ? conferenceContributeInfo.AdminStatus : conferenceContributeInfo.ContributationStatus;
				MailSender sender = new MailSender(conferenceMailServerMaster.MailServer);
				MailAddress from = new MailAddress(conferenceMailServerMaster.Mail);
				MailMessage message = Utility.GetMailContent(new MailModel
				{
					MailRemark = ConstValues.MailSubject.审稿结果,
					Language = conferenceMaster.IsInternational ? ConstValues.Language.En : ConstValues.Language.Cn,
					UserName = allAuthor,
					ConferenceId = conferenceMaster.ID,
					ConferenceName = conferenceNotice.ConferenceName,
					ConferenceNickName = conferenceMaster.ConferenceNickName,
					ContributeId = conferenceContributeInfo.ID,
					EssayTitle = conferenceContributeInfo.EssayTitle,
					Topic = DbContext.TopicMaster.AsNoTracking().FirstOrDefault(x => x.ID == conferenceContributeInfo.TopicId)?.TopicName,
					Essay = DbContext.EssayMaster.AsNoTracking().FirstOrDefault(x => x.ID == conferenceContributeInfo.EssayId)?.EssayType,
					Report = DbContext.ReportMaster.AsNoTracking().FirstOrDefault(x => x.ID == conferenceContributeInfo.ReportId)?.ReportType,
					Presenter = authorList.FirstOrDefault(x => x.IsPresenter)?.FullName,
					ContributationStatus = status == ConstValues.ContributationStatus.录用 ? Resources.StatusReviewAccept : Resources.StatusReviewReject,
					HasPdf = model.hasPdf == "true" ? true : false
				});

				foreach (var author in authorList)
				{
					MailAddress to = new MailAddress(author.Mail);
					message.To.Add(to);

					if (!string.IsNullOrWhiteSpace(author.CcMail))
					{
						foreach (string cc in author.CcMail.Split(ConstValues.chrSemicolon))
						{
							if (!string.IsNullOrWhiteSpace(cc) && cc.Contains(ConstValues.chrAt))
							{
								message.CC.Add(new MailAddress(cc.Trim()));
							}
						}
					}

					if (!string.IsNullOrWhiteSpace(conferenceMailServerMaster.CcMail))
					{
						foreach (string cc in conferenceMailServerMaster.CcMail.Split(ConstValues.chrSemicolon))
						{
							if (!string.IsNullOrWhiteSpace(cc) && cc.Contains(ConstValues.chrAt))
							{
								message.Bcc.Add(new MailAddress(cc.Trim()));
							}
						}
					}
				}

				if (status == ConstValues.ContributationStatus.录用 && conferenceNotice.HasAttachment && model.hasPdf == "true")
				{
					var pdfFilePath = Server.MapPath(ConstValues.MailAttachment) + conferenceNotice.ConferenceNickName + ConstValues.InvitationLetterPdf + "_" + dateTimeNow + ".pdf";
					message.Attachments.Add(new Attachment(pdfFilePath));
				}

				var mailTask = Task.Run(() =>
				{
					strMsg = sender.SendMail(from, message, conferenceMailServerMaster.Password);
				});

				var contributeResult = await DbContext.ConferenceContributeInfo
						.FirstOrDefaultAsync(x => x.ConferenceId == model.ConferenceId &&
							x.ID == model.ContributeId);

				if (contributeResult != null && string.IsNullOrEmpty(strMsg))
				{
					contributeResult.HasSend = true;
				}
			}

			await DbContext.SaveChangesAsync();

			return JsonCamelCase(Utility.CreateSuccessJsonResult(Resources.SuccessSendMail + strMsg),
					JsonRequestBehavior.AllowGet);
		}

		public async Task<JsonCamelCaseResult> GetJuniorEditData(string id, string conferenceId)
		{
			var result = await DbContext.ReviewInfo
					.FirstOrDefaultAsync(x => x.ConferenceId == conferenceId &&
						x.ContributeId == id &&
						x.UserId == LoginUser.UserID &&
						x.IsFinalReview == false);

			if (result == null)
			{
				return JsonCamelCase(Utility.CreateFailJsonResult(Resources.MsgRecordNotExist),
						JsonRequestBehavior.AllowGet);
			}

			return JsonCamelCase(Utility.CreateSuccessJsonResult(string.Empty, result),
					JsonRequestBehavior.AllowGet);
		}

		[HttpPost]
		[ValidateAntiForgeryToken]
		public async Task<FileResult> Export(string allId, string conferenceId)
		{
			string controller = RouteData.Values["controller"].ToString();
			string actionName = RouteData.Values["action"].ToString();
			Utility.InsertLog(LoginUser, Request.Url.ToString(), controller, actionName, "Index", conferenceId);

			var ids = allId.Split(ConstValues.chrComma);
			var sql = from contribute in DbContext.ConferenceContributeInfo.AsNoTracking().Where(x => ids.Contains(x.ID.ToString()))
				  join report in DbContext.ReportMaster.AsNoTracking().Where(x => x.Status == ConstValues.Status.正常)
					  on contribute.ReportId equals report.ID into reports
				  from report in reports.DefaultIfEmpty()
				  join essay in DbContext.EssayMaster.AsNoTracking().Where(x => x.Status == ConstValues.Status.正常)
					  on contribute.EssayId equals essay.ID into essays
				  from essay in essays.DefaultIfEmpty()
				  join topic in DbContext.TopicMaster.AsNoTracking().Where(x => x.Status == ConstValues.Status.正常)
					  on contribute.TopicId equals topic.ID into topics
				  from topic in topics.DefaultIfEmpty()
				  select new
				  {
					  ID = contribute.ID,
					  EssayTitle = contribute.EssayTitle,
					  ReportType = report.ReportType,
					  Abstract = contribute.Abstract,
					  ProgramAbstract = contribute.ProgramAbstract,
					  Keyword = contribute.Keyword,
					  AbstractFile = contribute.AbstractFile,
					  SupplementaryFile = contribute.SupplementaryFile,
					  Remark = contribute.Remark,
					  ReportId = contribute.ReportId,
					  TopicName = topic.TopicName,
					  EssayTypeName = essay.EssayType,
					  ContributationStatus = !string.IsNullOrEmpty(contribute.AdminStatus) ? contribute.AdminStatus : contribute.ContributationStatus,
					  ConferenceId = contribute.ConferenceId,
					  JournalId = contribute.JournalId
				  };

			var result = await sql.ToListAsync();

			var authorList = await DbContext.AuthorInfo.AsNoTracking()
					.Where(x => ids.Contains(x.ContributeId.ToString()))
					.ToListAsync();

			var export = Request.Cookies["_culture"].Value == ConstValues.Language.Cn ?
					Resources.export_reviewInfoCN : Resources.export_reviewInfoEN;

			XSSFWorkbook workbook;

			using (MemoryStream readStream = new MemoryStream(export))
			{
				workbook = new XSSFWorkbook(readStream);
				ISheet sheet = workbook.GetSheetAt(0);

				var count = 0;
				foreach (var model in result)
				{
					count += 1;
					IRow row = sheet.CreateRow(count);

					// 稿号
					int column = 0;
					ICell cell = row.CreateCell(column);
					cell.SetCellValue(model.ID);

					// 论文题目
					column++;
					cell = row.CreateCell(column);
					cell.SetCellValue(model.EssayTitle);

					// 作者
					var author = authorList.Where(x => x.ContributeId == model.ID)
						.OrderBy(x => x.Sort)
						.ThenByDescending(x => x.CreateDate)
						.ThenBy(x => x.FullName)
						.Select(x => x.FullName);
					column++;
					cell = row.CreateCell(column);
					cell.SetCellValue(string.Join(ConstValues.strSemicolon, author));

					// 报告类型
					column++;
					cell = row.CreateCell(column);
					cell.SetCellValue(!string.IsNullOrEmpty(model.ReportId) ? model.ReportType.ToString() : string.Empty);

					// 论文类型
					column++;
					cell = row.CreateCell(column);
					cell.SetCellValue(!string.IsNullOrEmpty(model.EssayTypeName) ? model.EssayTypeName.ToString() : string.Empty);

					// 专题名称
					column++;
					cell = row.CreateCell(column);
					cell.SetCellValue(!string.IsNullOrEmpty(model.TopicName) ? model.TopicName.ToString() : string.Empty);

					// 关键词
					column++;
					cell = row.CreateCell(column);
					cell.SetCellValue(model.Keyword);

					var conferenceMaster = await DbContext.ConferenceMaster.AsNoTracking()
							.FirstOrDefaultAsync(x => x.ID == model.ConferenceId);

					var folder = ConstValues.SystemWeb + ConstValues.chrSlash + conferenceMaster.ConferenceNickName;
					if (!string.IsNullOrWhiteSpace(model.JournalId))
					{
						var journalMaster = await DbContext.JournalMaster.AsNoTracking()
								.FirstOrDefaultAsync(x => x.ID == model.JournalId &&
									x.ConferenceId == model.ConferenceId);
						folder = folder + ConstValues.chrSlash + journalMaster.JournalId;
					}

					// 日程摘要
					column++;
					cell = row.CreateCell(column);
					if (!string.IsNullOrEmpty(model.ProgramAbstract))
					{
						cell.SetCellValue(Utility.GetNoHtml(model.ProgramAbstract));
					}
					else
					{
						cell.SetCellValue(string.Empty);
					}

					// 全文摘要
					column++;
					cell = row.CreateCell(column);
					if (!string.IsNullOrEmpty(model.Abstract))
					{
						cell.SetCellValue(Utility.GetNoHtml(model.Abstract));
					}
					else
					{
						cell.SetCellValue(string.Empty);
					}

					// 全文摘要文件
					column++;
					cell = row.CreateCell(column);
					if (!string.IsNullOrEmpty(model.AbstractFile))
					{
						FileInfo fi = new FileInfo(model.AbstractFile);
						XSSFHyperlink link = new XSSFHyperlink(HyperlinkType.Url);
						string fileFullPath = folder + ConstValues.chrSlash + fi.Name;
						link.Address = fileFullPath;
						cell.Hyperlink = link;
						cell.SetCellValue(fileFullPath);
					}

					// 全文文件
					column++;
					cell = row.CreateCell(column);
					if (!string.IsNullOrEmpty(model.SupplementaryFile))
					{
						FileInfo fi = new FileInfo(model.SupplementaryFile);
						XSSFHyperlink link = new XSSFHyperlink(HyperlinkType.Url);
						string fileFullPath = folder + ConstValues.chrSlash + fi.Name;
						link.Address = fileFullPath;
						cell.Hyperlink = link;
						cell.SetCellValue(fileFullPath);
					}
				}
			}

			MemoryStream exportStream = new MemoryStream();
			workbook.Write(exportStream);
			exportStream.Flush();
			exportStream.Position = 0;

			return File(exportStream, Application.Octet,
					$"export_reviewInfo_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx");
		}

		[HttpPost]
		[ValidateAntiForgeryToken]
		public async Task<ActionResult> BatchDownload(string conferenceId, string allId)
		{
			string controller = RouteData.Values["controller"].ToString();
			string actionName = RouteData.Values["action"].ToString();
			Utility.InsertLog(LoginUser, Request.Url.ToString(), controller, actionName, "Index", conferenceId);

			var ids = allId.Split(ConstValues.chrComma);
			var sql = from contribute in DbContext.ConferenceContributeInfo.AsNoTracking().Where(x => ids.Contains(x.ID.ToString()))
				  join report in DbContext.ReportMaster.AsNoTracking().Where(x => x.Status == ConstValues.Status.正常)
					    on contribute.ReportId equals report.ID into reports
				  from report in reports.DefaultIfEmpty()
				  join essay in DbContext.EssayMaster.AsNoTracking().Where(x => x.Status == ConstValues.Status.正常)
					    on contribute.EssayId equals essay.ID into essays
				  from essay in essays.DefaultIfEmpty()
				  join topic in DbContext.TopicMaster.AsNoTracking().Where(x => x.Status == ConstValues.Status.正常)
					    on contribute.TopicId equals topic.ID into topics
				  from topic in topics.DefaultIfEmpty()
				  select new
				  {
					  ID = contribute.ID,
					  EssayTitle = contribute.EssayTitle,
					  ReportType = report.ReportType,
					  Abstract = contribute.Abstract,
					  ProgramAbstract = contribute.ProgramAbstract,
					  Keyword = contribute.Keyword,
					  AbstractFile = contribute.AbstractFile,
					  SupplementaryFile = contribute.SupplementaryFile,
					  Remark = contribute.Remark,
					  ReportId = contribute.ReportId,
					  TopicName = topic.TopicName,
					  EssayTypeName = essay.EssayType,
					  ContributationStatus = !string.IsNullOrEmpty(contribute.AdminStatus) ? contribute.AdminStatus : contribute.ContributationStatus,
					  ConferenceId = contribute.ConferenceId,
					  JournalId = contribute.JournalId
				  };

			var result = await sql.ToListAsync();

			var authorList = await DbContext.AuthorInfo.AsNoTracking()
					.Where(x => ids.Contains(x.ContributeId.ToString()))
					.ToListAsync();

			var export = Request.Cookies["_culture"].Value == ConstValues.Language.Cn ?
					Resources.export_reviewInfoCN : Resources.export_reviewInfoEN;

			XSSFWorkbook workbook;

			List<string> fileList = new List<string>();

			using (MemoryStream readStream = new MemoryStream(export))
			{
				workbook = new XSSFWorkbook(readStream);
				ISheet sheet = workbook.GetSheetAt(0);

				var count = 0;
				foreach (var model in result)
				{
					count += 1;
					IRow row = sheet.CreateRow(count);

					// 稿号
					int column = 0;
					ICell cell = row.CreateCell(column);
					cell.SetCellValue(model.ID);

					// 论文题目
					column++;
					cell = row.CreateCell(column);
					cell.SetCellValue(model.EssayTitle);

					// 作者
					var author = authorList.Where(x => x.ContributeId == model.ID)
						.OrderBy(x => x.Sort)
						.ThenByDescending(x => x.CreateDate)
						.ThenBy(x => x.FullName)
						.Select(x => x.FullName);
					column++;
					cell = row.CreateCell(column);
					cell.SetCellValue(string.Join(ConstValues.strSemicolon, author));

					// 报告类型
					column++;
					cell = row.CreateCell(column);
					cell.SetCellValue(!string.IsNullOrEmpty(model.ReportId) ? model.ReportType.ToString() : string.Empty);

					// 论文类型
					column++;
					cell = row.CreateCell(column);
					cell.SetCellValue(!string.IsNullOrEmpty(model.EssayTypeName) ? model.EssayTypeName.ToString() : string.Empty);

					// 专题名称
					column++;
					cell = row.CreateCell(column);
					cell.SetCellValue(!string.IsNullOrEmpty(model.TopicName) ? model.TopicName.ToString() : string.Empty);

					// 关键词
					column++;
					cell = row.CreateCell(column);
					cell.SetCellValue(model.Keyword);

					var conferenceMaster = await DbContext.ConferenceMaster.AsNoTracking()
							.FirstOrDefaultAsync(x => x.ID == model.ConferenceId);

					var folder = ConstValues.SystemWeb + ConstValues.chrSlash + ConstValues.Uploads.Replace(ConstValues.strWave, string.Empty) + conferenceMaster.ConferenceNickName;
					if (!string.IsNullOrWhiteSpace(model.JournalId))
					{
						var journalMaster = await DbContext.JournalMaster.AsNoTracking()
								.FirstOrDefaultAsync(x => x.ID == model.JournalId &&
									x.ConferenceId == model.ConferenceId);
						folder = folder + ConstValues.chrSlash + journalMaster.JournalId;
					}

					// 日程摘要
					column++;
					cell = row.CreateCell(column);
					if (!string.IsNullOrEmpty(model.ProgramAbstract))
					{
						cell.SetCellValue(Utility.ChangeSubSupForExcel(workbook, model.ProgramAbstract));
					}
					else
					{
						cell.SetCellValue(string.Empty);
					}

					// 全文摘要
					column++;
					cell = row.CreateCell(column);
					if (!string.IsNullOrEmpty(model.Abstract))
					{
						cell.SetCellValue(Utility.ChangeSubSupForExcel(workbook, model.Abstract));
					}
					else
					{
						cell.SetCellValue(string.Empty);
					}

					// 全文摘要文件
					column++;
					cell = row.CreateCell(column);
					if (!string.IsNullOrEmpty(model.AbstractFile))
					{
						FileInfo fi = new FileInfo(model.AbstractFile);
						XSSFHyperlink link = new XSSFHyperlink(HyperlinkType.Url);
						string fileFullPath = folder + ConstValues.chrSlash + fi.Name;
						link.Address = fileFullPath;
						cell.Hyperlink = link;
						cell.SetCellValue(fileFullPath);
						fileList.Add(model.AbstractFile);
					}

					// 全文文件
					column++;
					cell = row.CreateCell(column);
					if (!string.IsNullOrEmpty(model.SupplementaryFile))
					{
						FileInfo fi = new FileInfo(model.SupplementaryFile);
						XSSFHyperlink link = new XSSFHyperlink(HyperlinkType.Url);
						string fileFullPath = folder + ConstValues.chrSlash + fi.Name;
						link.Address = fileFullPath;
						cell.Hyperlink = link;
						cell.SetCellValue(fileFullPath);
						fileList.Add(model.SupplementaryFile);
					}
				}
			}

			MemoryStream exportStream = new MemoryStream();
			workbook.Write(exportStream);
			exportStream.Flush();
			exportStream.Position = 0;

			var excelName = $"export_reviewInfo_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx";

			string conferenceNickName = (await DbContext.ConferenceMaster.AsNoTracking()
					.FirstOrDefaultAsync(x => x.Status == ConstValues.Status.正常 && x.ID == conferenceId))
					?.ConferenceNickName;
			string excelfolder = Server.MapPath(Path.Combine(ConstValues.Uploads, conferenceNickName));

			FileStream fs = new FileStream(Path.Combine(excelfolder, excelName), FileMode.CreateNew, FileAccess.ReadWrite);

			exportStream.CopyTo(fs);
			exportStream.Dispose();
			fs.Dispose();

			MemoryStream memoryStream = new MemoryStream();
			ZipOutputStream zipStream = new ZipOutputStream(memoryStream);
			zipStream.SetLevel(3);

			using (FileStream fileWrite = new FileStream(Path.Combine(excelfolder, excelName), FileMode.OpenOrCreate))
			{
				var newExcelFile = Path.Combine(excelfolder, excelName);
				ZipEntry newExcelEntry = new ZipEntry(Path.GetFileName(newExcelFile));
				FileInfo nfi = new FileInfo(newExcelFile);
				newExcelEntry.DateTime = nfi.LastWriteTime;
				newExcelEntry.Size = nfi.Length;
				zipStream.PutNextEntry(newExcelEntry);
				StreamUtils.Copy(fileWrite, zipStream, new byte[4096]);
				zipStream.CloseEntry();

				foreach (string file in fileList)
				{
					var newFile = Server.MapPath(file);
					ZipEntry newEntry = new ZipEntry(Path.GetFileName(newFile));
					FileInfo fi = new FileInfo(newFile);
					newEntry.DateTime = fi.LastWriteTime;
					newEntry.Size = fi.Length;
					zipStream.PutNextEntry(newEntry);
					using (FileStream streamReader = System.IO.File.OpenRead(newFile))
					{
						StreamUtils.Copy(streamReader, zipStream, new byte[4096]);
					}
					zipStream.CloseEntry();
				}

				zipStream.IsStreamOwner = false;
				zipStream.Close();

				memoryStream.Position = 0;
				var downloadFileName = conferenceNickName + ConstValues.chrUnderline
							+ DateTime.Now.ToString("yyyyMMddHHmm")
							+ ".zip";
				return File(memoryStream, Application.Octet, downloadFileName);
			}
		}

		[HttpPost]
		[ValidateAntiForgeryToken]
		[Route("AdminModify/{ConferenceId}")]
		public async Task<JsonResult> AdminModify(ReviewDataModel model)
		{
			string controller = RouteData.Values["controller"].ToString();
			string actionName = RouteData.Values["action"].ToString();
			Utility.InsertLog(LoginUser, Request.Url.ToString(), controller, actionName, "Index", model.ConferenceId);

			var result = await DbContext.ConferenceContributeInfo
					.FirstOrDefaultAsync(x => x.ID == model.ContributeId);

			var scheduleInfo = await DbContext.ScheduleInfo.AsNoTracking()
					.FirstOrDefaultAsync(x => x.ContributeId == model.ContributeId &&
						x.Status == ConstValues.ScheduleStatus.已安排);

			if (scheduleInfo != null && result.AdminStatus != model.ContributationStatus)
			{
				return JsonCamelCase(Utility.CreateFailJsonResult(Resources.MsgScheduleCanNotAdminModify),
						JsonRequestBehavior.AllowGet);
			}

			if (result == null)
			{
				return JsonCamelCase(Utility.CreateFailJsonResult(Resources.MsgRecordNotExist),
						JsonRequestBehavior.AllowGet);
			}

			result.AdminStatus = model.AdminStatus;
			result.AdminRemark = model.AdminRemark;
			result.AdminUserName = LoginUser.UserName;
			result.AdminDate = DateTime.Now;

			await DbContext.SaveChangesAsync();

			return JsonCamelCase(Utility.CreateSuccessJsonResult(Resources.SuccessSubmit),
					JsonRequestBehavior.AllowGet);
		}
	}
}